import datetime
import math
import re
import logging
from logging import handlers
import platform
import serial.tools.list_ports
import sys
import time
import traceback
import serial
import hmac
import xlwt
import decimal

from cmd_list import init_cmd, socket_cmd, http_cmd, mqtt_cmd, ftp_cmd, lte_cmd, file_cmd, bt_cmd, audio_cmd, http_break_download_cmd, aliyun_one_device_one_secret_cmd, aliyun_one_product_one_secret_cmd, pb_cmd, QC_init_cmd, QC_http_cmd, QC_socket_cmd, NB_lte_cmd

test_cmd_count, check_fail_count, timeout_count = 0, 0, 0

start_time = time.time()

baud_rate = 921600
system_cate = platform.system()

# zhaoxu
# aliyun_info = {
#     "product_key": "a1HvZlnlln9",
#     "device_name": "862167059989081",
#     "device_secret": "b3a852584f90ebe52532d00c7f93c856",
#     "product_secret": "H30ODdZz3hKWfPSB"
# }

# Jeremy
aliyun_info = {
    "product_key": "a1K4TWp6E6z",
    "device_name": "866714044885753",
    "device_secret": "42cdcd7bc6bf02b16b14c09864fe5205",
    "product_secret": "oqBAqpeFwQTKyn4M"
}


def get_hex(bytes_data):
    l = [hex(i) for i in bytes_data]
    return " ".join(l)


def log_com_read_match(cmd, res):
    global check_fail_count, sheet2_row, sheet1_index
    if len(res) > 300:
        log.debug(f"收←◆[{len(res)}字节，前300字节]:{res[0:300]}...")
        log.debug(f"收←◆HEX DATA[{len(res)}字节，前300字节]:{get_hex(res)[0:300]}...")
    else:
        log.debug(f"收←◆[{len(res)}字节]:{res}")
        log.debug(f"收←◆HEX DATA[{len(res)}字节]:{get_hex(res)}")
    try:
        match_res = re.search(cmd["match"], res.decode(encoding='utf-8'))
    except UnicodeDecodeError:
        log.error(traceback.format_exc())
        match_res = True
    if match_res:
        log.debug(f"AT命令【{cmd['cmd'][0:100]}】执行结果校验SUCCESS")
        at_cmd_list[sheet1_index]["success"] += 1
        sheet1.write(sheet1_index, 2, at_cmd_list[sheet1_index]["success"])
    else:
        log.error(f"AT命令【{cmd['cmd'][0:100]}】执行结果校验FAIL")
        check_fail_count = check_fail_count + 1
        sheet2.write(sheet2_row, 0, cmd["cmd"])
        sheet2.write(sheet2_row, 1, cmd["match"])
        try:
            sheet2.write(sheet2_row, 2, res.decode(encoding='utf-8'))
        except UnicodeDecodeError:
            sheet2.write(sheet2_row, 2, "解码异常")
            log.error(traceback.format_exc())
        sheet2.write(sheet2_row, 3, "匹配结果异常")
        sheet2_row += 1
        at_cmd_list[sheet1_index]["fail"] += 1
        sheet1.write(sheet1_index, 3, at_cmd_list[sheet1_index]["fail"])

    sheet1_index += 1


def log_com_read(res, timeout=False):
    global sheet1_index
    if not timeout:
        at_cmd_list[sheet1_index]["success"] += 1
        sheet1.write(sheet1_index, 2, at_cmd_list[sheet1_index]["success"])
        sheet1_index += 1
    if len(res) > 300:
        log.debug(f"收←◆[{len(res)}字节，前300字节]:{res[0:300]}...")
        log.debug(f"收←◆HEX DATA[{len(res)}字节，前300字节]:{get_hex(res)[0:300]}...")
    else:
        log.debug(f"收←◆[{len(res)}字节]:{res}")
        log.debug(f"收←◆HEX DATA[{len(res)}字节]:{get_hex(res)}")


def send_read(cmd, data, is_hex=False):
    global timeout_count, test_cmd_count, sheet2_row, sheet1_row, sheet1_index
    log.debug(f"发→◇{data}")
    test_cmd_count = test_cmd_count + 1
    if is_hex:
        ser.write(data)
    else:
        ser.write(data.encode(encoding="utf-8"))
    res = b""
    timeout = cmd.get("timeout")

    if not gen_sheet1_cmd:
        sheet1.write(sheet1_row, 0, cmd["cmd"])
        sheet1.write(sheet1_row, 1, cmd["match"])
        sheet1.write(sheet1_row, 2, 0)
        sheet1.write(sheet1_row, 3, 0)
        sheet1.write(sheet1_row, 4, 0)

        at_cmd_list.append({
            "success": 0,
            "fail": 0,
            "timeout": 0
        })
        sheet1_row += 1

    if cmd.get("wait") is None:
        time.sleep(0.05)
        while ser.in_waiting == 0:
            time.sleep(0.01)
        tmp = ser.read(ser.in_waiting)
        res = res + tmp
        log_com_read(res)
    else:
        while True:
            tmp = ser.read(ser.in_waiting)
            res = res + tmp
            if cmd.get("wait") in res:
                log_com_read(res)
                break
            else:
                timeout = decimal.Decimal(timeout) - decimal.Decimal("0.1")
                if timeout == 0:
                    log_com_read(res, timeout=True)
                    log.error(f"AT命令【{cmd['cmd'][0:100]}】执行结果等待超时FAIL")
                    timeout_count = timeout_count + 1
                    sheet2.write(sheet2_row, 0, cmd["cmd"])
                    sheet2.write(sheet2_row, 1, cmd["match"])
                    try:
                        sheet2.write(
                            sheet2_row, 2, res.decode(encoding='utf-8'))
                    except UnicodeDecodeError:
                        sheet2.write(sheet2_row, 2, "解码异常")
                        log.error(traceback.format_exc())
                    sheet2.write(sheet2_row, 3, "等待结果超时")
                    sheet2_row += 1
                    at_cmd_list[sheet1_index]["timeout"] += 1
                    sheet1.write(sheet1_index, 4,
                                 at_cmd_list[sheet1_index]["timeout"])
                    sheet1_index += 1
                    break
                time.sleep(0.1)
    log.debug(
        "------------------------------------------------------------------------------------------------------------------------")
    return res


def send_read_match(cmd, data, is_hex=False):
    global timeout_count, test_cmd_count, sheet1_row, sheet2_row, sheet1_index, gen_sheet1_cmd
    log.debug(f"发→◇{data}")
    test_cmd_count = test_cmd_count + 1
    if is_hex:
        ser.write(data)
    else:
        ser.write(data.encode(encoding="utf-8"))
    res = b""
    timeout = cmd.get("timeout")

    if not gen_sheet1_cmd:
        sheet1.write(sheet1_row, 0, cmd["cmd"])
        sheet1.write(sheet1_row, 1, cmd["match"])
        sheet1.write(sheet1_row, 2, 0)
        sheet1.write(sheet1_row, 3, 0)
        sheet1.write(sheet1_row, 4, 0)

        at_cmd_list.append({
            "success": 0,
            "fail": 0,
            "timeout": 0
        })
        sheet1_row += 1

    if cmd.get("wait") is None:
        time.sleep(0.05)
        while ser.in_waiting == 0:
            time.sleep(0.01)
        tmp = ser.read(ser.in_waiting)
        res = res + tmp
        log_com_read_match(cmd, res)
    else:
        while True:
            tmp = ser.read(ser.in_waiting)
            res = res + tmp
            if cmd.get("wait") in res:
                log_com_read_match(cmd, res)
                break
            else:
                timeout = decimal.Decimal(timeout) - decimal.Decimal("0.1")
                if timeout == 0:
                    log_com_read(res, timeout=True)
                    log.error(f"AT命令【{cmd['cmd'][0:100]}】执行结果等待超时FAIL")
                    timeout_count = timeout_count + 1
                    sheet2.write(sheet2_row, 0, cmd["cmd"])
                    sheet2.write(sheet2_row, 1, cmd["match"])
                    try:
                        sheet2.write(
                            sheet2_row, 2, res.decode(encoding='utf-8'))
                    except UnicodeDecodeError:
                        sheet2.write(sheet2_row, 2, "解码异常")
                        log.error(traceback.format_exc())
                    sheet2.write(sheet2_row, 3, "等待结果超时")
                    sheet2_row += 1
                    at_cmd_list[sheet1_index]["timeout"] += 1
                    sheet1.write(sheet1_index, 4,
                                 at_cmd_list[sheet1_index]["timeout"])
                    sheet1_index += 1
                    break
                time.sleep(0.1)
    log.debug(
        "------------------------------------------------------------------------------------------------------------------------")
    return res


def exec_cmd_list(cmd_list, group_title):
    global sheet1_index, sheet1_row, group_xf, gen_sheet1_cmd

    if not gen_sheet1_cmd:
        sheet1.write_merge(sheet1_row, sheet1_row, 0, 4, group_title, group_xf)
        sheet1_row += 1
        at_cmd_list.append(group_title)

    sheet1_index += 1

    for cmd in cmd_list:
        if cmd.get("enter") is None:
            if cmd.get("loop") is None:
                send_read_match(cmd, f"{cmd['cmd']}\r\n")
            else:
                for i in range(cmd["loop"]):
                    send_read_match(cmd, f"{cmd['cmd']}\r\n")
        else:
            if cmd.get("loop") is None:
                if cmd.get("hex"):
                    send_read_match(cmd, bytes.fromhex(cmd["cmd"]), True)
                else:
                    send_read_match(cmd, cmd["cmd"])
            else:
                for i in range(cmd["loop"]):
                    if cmd.get("hex"):
                        send_read_match(cmd, bytes.fromhex(cmd["cmd"]), True)
                    else:
                        send_read_match(cmd, cmd["cmd"])


def http_break_download_test(test_file_url):
    exec_cmd_list(http_break_download_cmd.http_break_download_cmd,
                  "HTTPBREAKDOWNLOAD")
    cmd = {
        "cmd": 'AT+HTTPSSL=1',
        "match": 'AT\+HTTPSSL=1\s{4}OK\s{2}'
    }
    if "https" in test_file_url:
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": f'AT+HTTPPARA="URL","{test_file_url}"',
        "match": '\s{4}OK\s{2}'
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    start = 0
    end = 299999
    i = start
    j = end
    while True:
        cmd = {
            "cmd": f'AT+HTTPPARA=BREAK,{i}',
            "match": '\s{4}OK\s{2}'
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        cmd = {
            "cmd": f'AT+HTTPPARA=BREAKEND,{j}',
            "match": '\s{4}OK\s{2}'
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        cmd = {
            "cmd": 'AT+HTTPACTION=0',
            "match": 'AT\+HTTPACTION=0\s{4}OK\s{4}\+HTTPACTION: 0,206,\d+\s{2}',
            "wait": b'+HTTPACTION:',
            "timeout": 60
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        cmd = {
            "cmd": 'AT+HTTPREAD',
            "match": '\s{2}OK\s{2}',
            "wait": b'\r\nOK\r\n',
            "timeout": 60
        }
        res = send_read(cmd, f'{cmd.get("cmd")}\r\n')
        if str(end + 1).encode(encoding="utf-8") not in res:
            break
        i += end + 1
        j += end + 1
    cmd = {
        "cmd": 'AT+HTTPTERM',
        "match": 'AT\+HTTPTERM\s{4}OK\s{2}',
        "wait": b'\r\nOK\r\n',
        "timeout": 10
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+SAPBR=0,1',
        "match": 'AT\+SAPBR=0,1\s{4}OK\s{2}',
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    log.debug('http_break_download_test SUCCESS')


def aliyun_test(mode, loop):
    if mode == 0:
        exec_cmd_list(
            aliyun_one_device_one_secret_cmd.aliyun_one_device_one_secret_cmd, "ALIYUN")
        # 拼接加密前明文
        message = b'clientId' + aliyun_info.get("device_name").encode('utf-8') + b'deviceName' + aliyun_info.get(
            "device_name").encode("utf-8") + b'productKey' + aliyun_info.get("product_key").encode('utf-8')
        key = aliyun_info.get("device_secret").encode('utf-8')
        # 使用HMACMD5算法用设备密钥加密明文
        sign = hmac.new(key, message, digestmod='MD5')
        # 拼接http_post发送信息
        post_info = f'productKey={aliyun_info.get("product_key")}&sign={sign.hexdigest()}&clientId={aliyun_info.get("device_name")}&deviceName={aliyun_info.get("device_name")}'
        get_aliyun_info_res, res = aliyun_get_mqtt_login_info(post_info)
        if get_aliyun_info_res is False:
            log.warning("获取Aliyun登录信息失败")
            return
        aliyun_connect_test(res, loop)
    else:
        exec_cmd_list(
            aliyun_one_product_one_secret_cmd.aliyun_one_product_one_secret_cmd, "ALIYUN")
        # 拼接明文
        message = f'deviceName{aliyun_info.get("device_name")}productKey{aliyun_info.get("product_key")}random123456'.encode(
        )
        key = aliyun_info.get("product_secret").encode('GB2312')
        # 使用HMACMD5算法用设备密钥加密明文
        sign = hmac.new(key, message, digestmod='MD5')
        # 拼接http_post发送信息
        post_info = f'productKey={aliyun_info.get("product_key")}&deviceName={aliyun_info.get("device_name")}&random=123456&sign={sign.hexdigest()}&signMethod=HmacMD5'
        get_aliyun_info_res, res = aliyun_get_mqtt_login_info(post_info)
        if get_aliyun_info_res is False:
            log.warning("获取Aliyun登录信息失败")
            return
        res = res.decode(encoding="utf-8")
        pattern = re.compile(r'"deviceSecret":"\w+"')
        device_secret = pattern.findall(res)[0]
        device_secret = device_secret.replace(
            '"deviceSecret":', '').replace('"', '')
        cmd = {
            "cmd": 'AT+HTTPTERM',
            "match": 'AT\+HTTPTERM\s{4}OK\s{2}',
            "wait": b'\r\nOK\r\n',
            "timeout": 10
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        message = f'clientId{aliyun_info.get("device_name")}deviceName{aliyun_info.get("device_name")}productKey{aliyun_info.get("product_key")}'.encode(
        )
        key = device_secret.encode('GB2312')
        # 使用HMACMD5算法用设备密钥加密明文
        sign = hmac.new(key, message, digestmod='MD5')
        # 拼接http_post发送信息
        post_info = f'productKey={aliyun_info.get("product_key")}&sign={sign.hexdigest()}&clientId={aliyun_info.get("device_name")}&deviceName={aliyun_info.get("device_name")}'
        cmd = {
            "cmd": 'AT+HTTPINIT',
            "match": 'AT\+HTTPINIT\s{4}OK\s{2}',
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        cmd = {
            "cmd": 'AT+HTTPPARA="URL","https://iot-auth.cn-shanghai.aliyuncs.com/auth/devicename"',
            "match": '\s{4}OK\s{2}',
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        cmd = {
            "cmd": 'AT+HTTPPARA="USER_DEFINED","Content-Type: application/x-www-form-urlencoded"',
            "match": '\s{4}OK\s{2}',
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        get_aliyun_info_res, res = aliyun_get_mqtt_login_info(post_info)
        if get_aliyun_info_res is False:
            log.warning("获取Aliyun登录信息失败")
            return
        aliyun_connect_test(res, loop)

    # 断开mqtt连接
    cmd = {
        "cmd": 'AT+MDISCONNECT',
        "match": '\s{4}OK\s{2}',
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+MIPCLOSE',
        "match": '\s{4}OK\s{2}',
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+SAPBR=0,1',
        "match": '.*',
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')


def aliyun_get_mqtt_login_info(post_info):
    cmd = {
        "cmd": f'AT+HTTPDATA={len(post_info)},20000',
        "match": '\s{4}DOWNLOAD\s{2}'
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": post_info,
        "match": '\s{2}OK\s{2}'
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+HTTPACTION=1',
        "match": 'AT\+HTTPACTION=1\s{4}OK\s{4}\+HTTPACTION: 1,200,\d+\s{2}',
        "wait": b'+HTTPACTION: ',
        "timeout": 5
    }
    http_get_aliyun_info_res = send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    if not b'200' in http_get_aliyun_info_res:
        return False, http_get_aliyun_info_res
    cmd = {
        "cmd": 'AT+HTTPREAD',
        "match": '\s{2}OK\s{2}',
        "wait": b'OK',
        "timeout": 5
    }
    res = send_read(cmd, f'{cmd.get("cmd")}\r\n')
    return True, res


def aliyun_connect_test(res, loop=10):
    res = res.decode(encoding="utf-8")
    pattern1 = re.compile(r'"iotId":"\w+"')
    iotId = pattern1.findall(res)[0]
    iotId = iotId.replace('"iotId":', '').replace('"', '')
    pattern2 = re.compile(r'"iotToken":"[\^\d\w]+"')
    iotToken = pattern2.findall(res)[0]
    iotToken = iotToken.replace('"iotToken":', '').replace('"', '')
    cmd = {
        "cmd": 'AT+HTTPTERM',
        "match": 'AT\+HTTPTERM\s{4}OK\s{2}',
        "wait": b'\r\nOK\r\n',
        "timeout": 10
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": f'AT+MCONFIG="{aliyun_info.get("device_name")}","{iotId}","{iotToken}"',
        "match": '\s{4}OK\s{2}',
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+SSLMIPSTART="' + aliyun_info.get("product_key") + '.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883',
        "match": '\s{4}OK\s{4}CONNECT OK\s{2}',
        "wait": b'CONNECT OK',
        "timeout": 5
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+MCONNECT=1,300',
        "match": 'AT\+MCONNECT=1,300\s{4}OK\s{4}CONNACK OK\s{2}',
        "wait": b'CONNACK OK',
        "timeout": 5
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+MSUB="/' + aliyun_info.get("product_key") + '/' + aliyun_info.get(
            "device_name") + '/user/Jeremy",0',
        "match": '\s{4}OK\s{4}SUBACK\s{2}',
        "wait": b'SUBACK',
        "timeout": 5
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    cmd = {
        "cmd": 'AT+MQTTMSGSET=0',
        "match": '\s{4}OK\s{2}',
    }
    send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
    for i in range(loop):
        cmd = {
            "cmd": 'AT+MPUB="/' + aliyun_info.get("product_key") + '/' + aliyun_info.get(
                "device_name") + '/user/Jeremy",0,0,"test0"',
            "match": '\s{4}OK\s{4}\+MSUB: "\/'+aliyun_info.get("product_key")+'\/\d+\/user\/Jeremy",5 byte,test0\s{2}',
            "wait": b'5 byte,test0\r\n',
            "timeout": 5
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')
        cmd = {
            "cmd": 'AT+MPUB="/' + aliyun_info.get("product_key") + '/' + aliyun_info.get(
                "device_name") + '/user/Jeremy",1,0,"test1"',
            "match": '\s{4}OK\s{4}PUBACK\s{4}\+MSUB: "\/' + aliyun_info.get("product_key") + '\/\d+\/user\/Jeremy",5 byte,test1\s{2}',
            "wait": b'5 byte,test1\r\n',
            "timeout": 5
        }
        send_read_match(cmd, f'{cmd.get("cmd")}\r\n')


def calc_cost_time():
    cost_time = math.floor(time.time() - start_time)
    cost_secs = cost_time % 60
    cost_days = math.floor(cost_time / 60 / 60 / 24)
    cost_hours = math.floor((cost_time - cost_days * 86400) / 60 / 60)
    cost_mins = math.floor(
        (cost_time - cost_days * 86400 - cost_hours * 3600) / 60)
    return cost_days, cost_hours, cost_mins, cost_secs


LOG_FORMAT = "%(asctime)s-%(levelname)s-%(message)s"
DATE_FORMAT = "%Y/%m/%d %H:%M:%S"

format_str = logging.Formatter(fmt=LOG_FORMAT, datefmt=DATE_FORMAT)

log = logging.getLogger("logger")
log.setLevel(logging.DEBUG)
sh = logging.StreamHandler()
sh.setFormatter(format_str)

# th = handlers.TimedRotatingFileHandler(
#     filename="log.txt", when="D", encoding='utf-8')
# th.setFormatter(format_str)

fh = handlers.RotatingFileHandler(
    filename="log.txt", mode="a", maxBytes=1024 * 1024 * 512, backupCount=10, encoding="utf-8")
fh.setFormatter(format_str)
log.addHandler(sh)
# log.addHandler(th)
log.addHandler(fh)


try:
    if len(sys.argv) == 2 and sys.argv[1] == '-h':
        print('''使用方法: 
Linux: python3 main.py {port}
Windows: python main.py {port}''')
        sys.exit()
    elif len(sys.argv) == 1:
        for com_port in serial.tools.list_ports.comports():
            print(com_port)
        if system_cate == 'Linux':
            port = f"/dev/ttyUSB{input('请输入设备端口号(只需要输入/dev/ttyUSB后数字):')}"
        else:
            port = f"COM{input('请输入设备端口号(只需要输入COM后数字):')}"
    elif len(sys.argv) == 2:
        port = sys.argv[1]
    else:
        print("输入参数有误,使用方法请添加帮助参数:-h")
        sys.exit()

    ser = serial.Serial(port=port, baudrate=baud_rate)

    AT_version = "Unknown"

    ser.write(b"ATI\r\n")
    ser.timeout = 0.3
    AT_version = re.findall("\d+", ser.read(100).decode())[-1:][0]

    heading_xf = xlwt.easyxf(
        'font: bold on, height 256; align: wrap on, vert centre, horiz center; pattern: pattern solid, fore-colour pale_blue; borders: top 1, bottom 1, left 1, right 1')

    group_xf = xlwt.easyxf(
        'font: bold on, height 256; align: wrap on, vert centre, horiz center; pattern: pattern solid, fore-colour gray25;')
    test_res_excel = xlwt.Workbook()
    sheet1 = test_res_excel.add_sheet("测试AT命令情况集合", cell_overwrite_ok=True)
    sheet2 = test_res_excel.add_sheet("测试失败集合", cell_overwrite_ok=True)

    sheet1.col(0).width = 256 * 80
    sheet1.col(1).width = 256 * 80

    sheet2.col(0).width = 256 * 80
    sheet2.col(1).width = 256 * 80
    sheet2.col(2).width = 256 * 80
    sheet2.col(3).width = 256 * 15

    sheet1_row, sheet2_row, sheet1_index = 1, 1, 0

    head1 = ["AT命令", "匹配规则", "成功次数", "匹配失败次数", "接收超时次数"]
    head2 = ["AT命令", "匹配规则", "实际返回", "失败原因"]

    for k, v in enumerate(head1):
        sheet1.write(0, k, v, heading_xf)

    sheet1_index += 1

    for k, v in enumerate(head2):
        sheet2.write(0, k, v, heading_xf)

    at_cmd_list = ["AT命令"]
    gen_sheet1_cmd = False

    com_name = "AirM2M"
    # com_name = "Quectel"
    # com_name = "Mlink"

    testMode = "single"

    if testMode == "single":
        if com_name == "AirM2M":
            exec_cmd_list(init_cmd.init_cmd, "INIT")
            # exec_cmd_list(socket_cmd.socket_cmd, "SOCKET")
            # exec_cmd_list(http_cmd.http_cmd, "HTTP")
            exec_cmd_list(mqtt_cmd.mqtt_cmd, "MQTT")
            # exec_cmd_list(ftp_cmd.ftp_cmd, "FTP")
            # exec_cmd_list(file_cmd.file_cmd, "FILE")
            # exec_cmd_list(audio_cmd.audio_cmd, "AUDIO")
            # exec_cmd_list(lte_cmd.lte_cmd, "LTE")
            # exec_cmd_list(bt_cmd.bt_cmd, "BLUETOOTH")
            # exec_cmd_list(pb_cmd.pb_cmd, "PHONEBOOK")
            # aliyun_test(0, 50)
            test_file_url = "https://test-wit-update.roistar.net/manage_file.cgi?action=download_file&devid=U0301020000039KB1&fid=1UmPaRY1Zwx6VdNH7BsypIbKGNN_6c5ea80c-65ba-4757-9bd4-781ac4de91b5.bin"
            # http_break_download_test(test_file_url)
            gen_sheet1_cmd = True
            sheet1_index = 1
        elif com_name == "Quectel":
            exec_cmd_list(QC_init_cmd.QC_init_cmd, "QCINIT")
            exec_cmd_list(QC_mqtt_cmd.QC_mqtt_cmd, "QCMQTT")
            exec_cmd_list(QC_http_cmd.QC_http_cmd, "QCHTTP")
            exec_cmd_list(QC_socket_cmd.QC_socket_cmd, "QCSOCKET")
            gen_sheet1_cmd = True
            sheet1_index = 1
        elif com_name == "Mlink":
            exec_cmd_list(NB_lte_cmd.NB_lte_cmd, "NBlte")
            # exec_cmd_list(NB_onenet_cmd.NB_onenet_cmd, "NBonenet")
            # exec_cmd_list(NB_ctwing_cmd.NB_ctwing_cmd, "NBctwing")
            gen_sheet1_cmd = True
            sheet1_index = 1
    elif testMode == "loop":
        if com_name == "AirM2M":
            while True:
                exec_cmd_list(init_cmd.init_cmd, "INIT")
                exec_cmd_list(socket_cmd.socket_cmd, "SOCKET")
                exec_cmd_list(http_cmd.http_cmd, "HTTP")
                exec_cmd_list(mqtt_cmd.mqtt_cmd, "MQTT")
                exec_cmd_list(ftp_cmd.ftp_cmd, "FTP")
                exec_cmd_list(file_cmd.file_cmd, "FILE")
                exec_cmd_list(audio_cmd.audio_cmd, "AUDIO")
                exec_cmd_list(lte_cmd.lte_cmd, "LTE")
                exec_cmd_list(bt_cmd.bt_cmd, "BLUETOOTH")
                exec_cmd_list(pb_cmd.pb_cmd, "PHONEBOOK")
                aliyun_test(0, 50)
                test_file_url = "https://test-wit-update.roistar.net/manage_file.cgi?action=download_file&devid=U0301020000039KB1&fid=1UmPaRY1Zwx6VdNH7BsypIbKGNN_6c5ea80c-65ba-4757-9bd4-781ac4de91b5.bin"
                http_break_download_test(test_file_url)
                gen_sheet1_cmd = True
                sheet1_index = 1
        elif com_name == "Quectel":
            while True:
                exec_cmd_list(QC_init_cmd.QC_init_cmd, "QCINIT")
                exec_cmd_list(QC_mqtt_cmd.QC_mqtt_cmd, "QCMQTT")
                exec_cmd_list(QC_http_cmd.QC_http_cmd, "QCHTTP")
                exec_cmd_list(QC_socket_cmd.QC_socket_cmd, "QCSOCKET")
                gen_sheet1_cmd = True
                sheet1_index = 1
        elif com_name == "Mlink":
            while True:
                exec_cmd_list(NB_lte_cmd.NB_lte_cmd, "NBlte")
                # exec_cmd_list(NB_onenet_cmd.NB_onenet_cmd, "NBonenet")
                # exec_cmd_list(NB_ctwing_cmd.NB_ctwing_cmd, "NBctwing")
                gen_sheet1_cmd = True
                sheet1_index = 1


except TypeError as te:
    log.error("发生了一个无法理解的异常")
    cost_days, cost_hours, cost_mins, cost_secs = calc_cost_time()
    log.debug(
        f"本次测试共成功执行命令{test_cmd_count}条，结果校验失败{check_fail_count}条，等待超时{timeout_count}条，程序共执行{cost_days}天{cost_hours}小时{cost_mins}分钟{cost_secs}秒")
    test_res_excel.save(
        f'AT_V{AT_version}版本AT命令测试结果{datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")}.xls')
    exceptionInfo = traceback.format_exc()
    log.error(exceptionInfo)
    index = 0
    for item in at_cmd_list:
        print(index, item)
        index += 1
    log.error(sheet1_index)
    log.error(type(sheet1_index))
    log.error(at_cmd_list[sheet1_index]["success"])
    sys.exit()
except KeyboardInterrupt as ke:
    log.debug("用户键盘事件退出...")
    cost_days, cost_hours, cost_mins, cost_secs = calc_cost_time()
    log.debug(
        f"本次测试共成功执行命令{test_cmd_count}条，结果校验失败{check_fail_count}条，等待超时{timeout_count}条，程序共执行{cost_days}天{cost_hours}小时{cost_mins}分钟{cost_secs}秒")
    test_res_excel.save(
        f'AT_V{AT_version}版本AT命令测试结果{datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")}.xls')
    sys.exit()
except serial.serialutil.SerialException as se:
    exceptionInfo = traceback.format_exc()
    log.error(exceptionInfo)
    if 'No such file or directory' in exceptionInfo:
        log.error('输入的端口不存在')
    if 'could not open port' in exceptionInfo:
        log.error('端口被占用,请检查是否有其他程序正在占用设备端口')
    if 'read failed: device reports readiness' in exceptionInfo:
        log.error('读取异常，建议重新连接模块测试')
    if 'ClearCommError failed' in exceptionInfo:
        log.error('连接异常，建议重新连接模块测试')
except Exception as e:
    log.error(traceback.format_exc())

cost_days, cost_hours, cost_mins, cost_secs = calc_cost_time()
log.debug(
    f"本次测试共成功执行命令{test_cmd_count}条，结果校验失败{check_fail_count}条，等待超时{timeout_count}条，程序共执行{cost_days}天{cost_hours}小时{cost_mins}分钟{cost_secs}秒")
test_res_excel.save(
    f'AT_V{AT_version}版本AT命令测试结果{datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")}.xls')
